﻿using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Threading;

using Holdem.Core.Configuration;

using NUnit.Framework;

namespace Test.Holdem.Configuration
{
    [TestFixture]
    public class HoldemIsolatedStorageFileStreamTest
    {
        private static string CreateFileName()
        {
            const string format = @".\holdem.isolated.file.stream{0}.xml";

            return String.Format(format, DateTime.Now.ToString("mm_dd_yyyy"));
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_WriteByte()
        {
            var savePath = CreateFileName();

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                const byte testBytes = (byte)'T';

                Assert.IsTrue(holdemStream.CanWrite);
                holdemStream.WriteByte(testBytes);
            }

            const byte expected = (byte)'T';
            byte actual;

            using (var testStraem = stream.OpenFile(savePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var holdemStream = new HoldemIsolatedStorageFileStream(testStraem);

                Assert.IsTrue(holdemStream.CanRead);
                actual = (byte)holdemStream.ReadByte();
            }

            Assert.AreEqual(expected, actual);

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_Write()
        {
            var savePath = CreateFileName();

            var bytes = new[] { (byte)'T', (byte)'E', (byte)'S', (byte)'T' };

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                Assert.IsTrue(holdemStream.CanWrite);
                holdemStream.Write(bytes, 0, bytes.Length);
            }

            var expected = new byte[4];

            using (var testStraem = stream.OpenFile(savePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var holdemStream = new HoldemIsolatedStorageFileStream(testStraem);

                Assert.IsTrue(holdemStream.CanRead);
                holdemStream.Read(expected, 0, expected.Length);
            }

            Assert.AreEqual(expected, bytes);

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_EndWrite()
        {
            var savePath = CreateFileName();

            var buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            var waits =
                new WaitHandle[]
                {
                    new AutoResetEvent(false)
                };

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                holdemStream.BeginWrite(
                    buffer,
                    0,
                    buffer.Length,
                    x =>
                    {
                        holdemStream.EndWrite(x);
                        ((AutoResetEvent)waits[0]).Set();
                    }, "test");

                WaitHandle.WaitAny(waits);
            }

            var actual = new byte[buffer.Length];

            using (var testStream = stream.OpenFile(savePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var holdemStream = new HoldemIsolatedStorageFileStream(testStream);

                holdemStream.BeginRead(
                    actual,
                    0,
                    actual.Length,
                    x =>
                    {
                        holdemStream.EndRead(x);
                        ((AutoResetEvent)waits[0]).Set();
                    }, "test1");

                WaitHandle.WaitAny(waits);
            }

            Assert.AreEqual(buffer, actual);

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);

        }

        [Test]
        public void HoldemIsolatedStorageFileStream_Position()
        {
            var savePath = CreateFileName();

            var buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            var waits =
                new WaitHandle[]
                {
                    new AutoResetEvent(false)
                };

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                holdemStream.BeginWrite(
                    buffer,
                    0,
                    buffer.Length,
                    x =>
                    {
                        holdemStream.EndWrite(x);
                        ((AutoResetEvent)waits[0]).Set();
                    }, "test");

                WaitHandle.WaitAny(waits);
            }

            var actual = new byte[buffer.Length];

            using (var testStream = stream.OpenFile(savePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var holdemStream = new HoldemIsolatedStorageFileStream(testStream);

                holdemStream.BeginRead(
                    actual,
                    0,
                    actual.Length,
                    x =>
                    {
                        holdemStream.Position = 1;
                        Assert.AreEqual(1, holdemStream.Position);
                        holdemStream.EndRead(x);
                        ((AutoResetEvent)waits[0]).Set();
                    }, "test1");

                WaitHandle.WaitAny(waits);
            }

            Assert.AreEqual(buffer, actual);

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_SetLength()
        {
            var savePath = CreateFileName();

            var buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            var waits =
                new WaitHandle[]
                {
                    new AutoResetEvent(false)
                };

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                holdemStream.BeginWrite(
                    buffer,
                    0,
                    buffer.Length,
                    x =>
                    {
                        holdemStream.SetLength(3);
                        Assert.AreEqual(3, holdemStream.Length);
                        holdemStream.EndWrite(x);
                        ((AutoResetEvent)waits[0]).Set();
                    }, "test");

                WaitHandle.WaitAny(waits);
            }

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_Length()
        {
            var savePath = CreateFileName();
            var buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                holdemStream.BeginWrite(
                    buffer,
                    0,
                    buffer.Length,
                    x =>
                    {
                        holdemStream.EndWrite(x);

                        holdemStream.SetLength(4);
                        Assert.AreEqual(4, holdemStream.Length);
                    }, "test");
            }

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_Seek()
        {
            var savePath = CreateFileName();

            var buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            var waits =
                new WaitHandle[]
                {
                    new AutoResetEvent(false)
                };

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                holdemStream.BeginWrite(
                    buffer,
                    0,
                    buffer.Length,
                    x =>
                    {
                        holdemStream.EndWrite(x);
                        ((AutoResetEvent)waits[0]).Set();
                    }, "test");

                WaitHandle.WaitAny(waits);
            }

            var actual = new byte[buffer.Length];

            using (var testStream = stream.OpenFile(savePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var holdemStream = new HoldemIsolatedStorageFileStream(testStream);

                holdemStream.BeginRead(
                    actual,
                    0,
                    actual.Length,
                    x =>
                    {
                        var seek = holdemStream.Seek(2, SeekOrigin.Begin);
                        Assert.AreEqual(2, seek);
                        holdemStream.EndRead(x);
                        ((AutoResetEvent)waits[0]).Set();
                    }, "test1");

                WaitHandle.WaitAny(waits);
            }

            Assert.AreEqual(buffer, actual);

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_CanSeek()
        {
            var savePath = CreateFileName();

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                var canSeek = holdemStream.CanSeek;

                Assert.IsTrue(canSeek);
            }

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_Flush()
        {
            var savePath = CreateFileName();

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                Assert.DoesNotThrow(holdemStream.Flush);
            }

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_Dispose()
        {
            var savePath = CreateFileName();

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                Assert.DoesNotThrow(holdemStream.Dispose);
            }

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_Dispose_True()
        {
            var savePath = CreateFileName();

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                Assert.DoesNotThrow(() => holdemStream.Dispose(true));
            }

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }

        [Test]
        public void HoldemIsolatedStorageFileStream_Dispose_False()
        {
            var savePath = CreateFileName();

            var stream = IsolatedStorageFile.GetUserStoreForApplication();

            using (var holdemStream = new HoldemIsolatedStorageFileStream(stream.CreateFile(savePath)))
            {
                Assert.DoesNotThrow(() => holdemStream.Dispose(false));
            }

            if (stream.FileExists(savePath))
                stream.DeleteFile(savePath);
        }
    }
}